<?php

namespace app\common\model;

//应用ApiApptoken表

use think\Model;

class ApiApptoken extends Model {

    protected $table = '__ADMIN_API_APP_TOKEN__';
    //只读字段,一旦写入，就无法更改。
    protected $readonly = ['app_id', 'apptoken'];
    // 新增自动完成列表
    protected $insert = [];
    //更新自动完成列表
    protected $update = [];
    //新增和更新自动完成列表
    protected $auto = []; 
   

    /**
     * 创建或刷新一个TOKEN
     * @param int $uid    
     * @param int $appTokenTime
     * @param int $appId
     * @return type
     */
    public static function refreshToken($uid,$appTokenTime,$appId = 0){
        $token = self::getToken($uid,$appId);  
        $ret = self::where("uid",$uid)->where("app_id",$appId)->find();       
        $data = [
            "uid"=>$uid,
            "app_id"=>$appId,
            "apptoken"=>$token,
            "app_tokenTime"=>$appTokenTime + time()              
         ];
        
        if($ret){
            $ret1 = self::where("id",$ret['id'])->update($data);
        }else{
            $ret1 = self::create($data);
        }
        $oldToken = $ret["apptoken"] ?? "";   
        $json = json_encode($data);
        cache("tk:" . $token,$json,$appTokenTime);
        //这里要注意删除过去失效的token缓存 ,避免造成资源浪费
        if($oldToken){
           cache("tk:" . $oldToken,null);
        }
        return $token;
    }
    
    /**
     * 生成一个TOKEN 
     * @param int $uid
     * @param int $appId
     * @return type
     */
    public static function getToken($uid ,$appId) {
        return md5($uid . $appId . time() . mt_rand(0, 9999));     
    }
     /**
     * 获取TOKEN数据,不验证
     * @param string $token
     * @return arr|ArrayAccess
     * @throws \Exception
     */
    public static function getTokenInfo($token){
        //如果要改成Cache要保持和写入时是一致     
        $cache =  cache("tk:" . $token);
        if($cache){
            $ret = json_decode($cache,true);
        }else{
            //若缓存不存在的兜底方案
            $ret = self::where("apptoken",$token)->find();
        }
        $time =  time();
             
        if(!$ret){
            throw new \Exception("token not valid");
        }       
    
        //重置缓存
        if(!$cache && $ret['app_tokenTime'] > $time){           
            $json = json_encode($ret);
            $appTokenTime = $ret['app_tokenTime']  - $time;
            cache("tk:" . $token,$json,$appTokenTime);
        }        
        return $ret;
    }
    
    /**
     * 验证TOKEN并返回会员ID,可选择是否同时验证APPID
     * @param string $token
     * @param int|false $appId
     * @return int
     * @throws \Exception
     */
    public static function checkToken($token ,$appId = false){
        $ret = self::getTokenInfo($token);         
        $time = time();
        if($ret['app_tokenTime'] < $time){
            throw new \Exception("token expired");
        }
        if($appId  && $ret['app_id'] !=  $appId){
            throw new \Exception("appid not valid");
        }                 
        return $ret['uid'];
    }    
   
    /**
     * 直接拿到一个TOKEN， 用于后台模拟     
     * @param int $uid
     * @param int $appId
     * @return string
     * @throws \Exception
     */
    public static function getUserToken($uid,$appId = 0){
        $ret = self::where("uid",$uid)->where("app_id",$appId)->find();
        if(!$ret){
            throw new \Exception("this app token not found");
        }
        if($ret['app_tokenTime'] < time()){
            throw new \Exception("this token not expired");
        }
        return $ret['apptoken'];
    }
    
          /**
     * 清除用户所有token、强制将其踢下线
     * @author 晓风<215628355@qq.com>
     * @param int $uid
     * @return boolean
     */    
    public static function clearUserToken($uid){
        $tokens = self::where("uid",$uid)->column("apptoken");
        self::where("uid",$uid)->delete();
        foreach ($tokens as $token){
             cache("tk:" . $token,null);
        }
        return true;
    }
}